{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "d2574e6e",
   "metadata": {},
   "source": [
    "# 迭代器与生成器"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "9808b043",
   "metadata": {},
   "source": [
    "## 迭代器"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "3c1d71cd",
   "metadata": {},
   "source": [
    "可迭代对象可以在 for 循环中使用："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "fbe27bff",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "4\n",
      "6\n"
     ]
    }
   ],
   "source": [
    "x = [2, 4, 6]\n",
    "\n",
    "for n in x:\n",
    "    print(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d39d937",
   "metadata": {},
   "source": [
    "之所以可以被for循环迭代，是因为这些对象拥有一个迭代器，可以用`.__iter__()`方法获得："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "dbe4ed0f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<list_iterator at 0x1118b32b0>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.__iter__()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "6aaede68",
   "metadata": {},
   "source": [
    "一个迭代器需要满足两个条件：\n",
    "\n",
    "- `.__iter__()`方法返回自身\n",
    "- `.__next__()`方法返回下一个迭代值，当迭代完成后，抛出一个StopIteration异常"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a28b33d4",
   "metadata": {},
   "outputs": [],
   "source": [
    "i = x.__iter__()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "48eefe88",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "i.__iter__() is i"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ac5c06dc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "i.__next__()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b415ec70",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "i.__next__()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3bb71680",
   "metadata": {},
   "source": [
    "也可以调用`next()`函数迭代："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "afbd38dd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76a48082",
   "metadata": {},
   "source": [
    "没有元素时抛出异常："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "3a1bd2d2",
   "metadata": {},
   "outputs": [
    {
     "ename": "StopIteration",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "Input \u001b[0;32mIn [8]\u001b[0m, in \u001b[0;36m<cell line: 1>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mi\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__next__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[0;31mStopIteration\u001b[0m: "
     ]
    }
   ],
   "source": [
    "i.__next__()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e30d5fed",
   "metadata": {},
   "source": [
    "## 自定义迭代器\n",
    "\n",
    "自定义一个 list 的反序迭代器："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "43435709",
   "metadata": {},
   "outputs": [],
   "source": [
    "class ReverseListIterator(object):\n",
    "    \n",
    "    def __init__(self, list):\n",
    "        self.list = list\n",
    "        self.index = len(list)\n",
    "        \n",
    "    def __iter__(self):\n",
    "        return self\n",
    "    \n",
    "    def __next__(self):\n",
    "        self.index -= 1\n",
    "        if self.index >= 0:\n",
    "            return self.list[self.index]\n",
    "        else:\n",
    "            raise StopIteration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "a83e09a1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9\n",
      "8\n",
      "7\n",
      "6\n",
      "5\n",
      "4\n",
      "3\n",
      "2\n",
      "1\n",
      "0\n"
     ]
    }
   ],
   "source": [
    "x = range(10)\n",
    "for i in ReverseListIterator(x):\n",
    "    print(i)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "7365852d",
   "metadata": {},
   "source": [
    "## 生成器\n",
    "\n",
    "直接实现自定义类型迭代器比较麻烦，一个更简单的方法是使用生成器。例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "7da038bb",
   "metadata": {},
   "outputs": [],
   "source": [
    "def test_generator():\n",
    "    yield 1\n",
    "    yield 5\n",
    "    yield 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "ac38cf42",
   "metadata": {},
   "outputs": [],
   "source": [
    "g = test_generator()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce2d8532",
   "metadata": {},
   "source": [
    "生成器也是满足迭代器定义的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "8ad80eb3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g.__iter__() is g"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e84bceb",
   "metadata": {},
   "source": [
    "生成器会按照定义时，`yield`产出的值进行迭代："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "e60a5032",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(g)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "e3c0bbc3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(g)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "a2122dbc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(g)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0040242b",
   "metadata": {},
   "source": [
    "迭代结束后，抛出异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "fb54179d",
   "metadata": {},
   "outputs": [
    {
     "ename": "StopIteration",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "Input \u001b[0;32mIn [17]\u001b[0m, in \u001b[0;36m<cell line: 1>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;43mnext\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mg\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[0;31mStopIteration\u001b[0m: "
     ]
    }
   ],
   "source": [
    "next(g)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "b5f5d0bc",
   "metadata": {},
   "source": [
    "逆序函数也可以用生成器实现："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "61ed97ff",
   "metadata": {},
   "outputs": [],
   "source": [
    "def my_reverse(data):\n",
    "    for i in data[::-1]:\n",
    "        yield i"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "54787e3b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "e\n",
      "d\n",
      "c\n",
      "b\n",
      "a\n"
     ]
    }
   ],
   "source": [
    "for i in my_reverse('abcde'):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e1950b03",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
